﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace BackupContracts.Tasks
{
    public enum ScheduleType
    {
        OneTime,
        Daily,
        Weekly,
        Monthly,
    }

    public class Schedule : ModelBase
    {
        public Schedule()
        {
            DaysOfWeek = new ObservableCollection<SelectablePeriod>();
            DaysOfWeek.Add(new SelectablePeriod() { Id = (int)DayOfWeek.Friday, SelectablePeriodType = SelectablePeriodType.DayOfWeek });
            DaysOfWeek.Add(new SelectablePeriod() { Id = (int)DayOfWeek.Monday, SelectablePeriodType = SelectablePeriodType.DayOfWeek });
            DaysOfWeek.Add(new SelectablePeriod() { Id = (int)DayOfWeek.Saturday, SelectablePeriodType = SelectablePeriodType.DayOfWeek });
            DaysOfWeek.Add(new SelectablePeriod() { Id = (int)DayOfWeek.Sunday, SelectablePeriodType = SelectablePeriodType.DayOfWeek });
            DaysOfWeek.Add(new SelectablePeriod() { Id = (int)DayOfWeek.Thursday, SelectablePeriodType = SelectablePeriodType.DayOfWeek });
            DaysOfWeek.Add(new SelectablePeriod() { Id = (int)DayOfWeek.Tuesday, SelectablePeriodType = SelectablePeriodType.DayOfWeek });
            DaysOfWeek.Add(new SelectablePeriod() { Id = (int)DayOfWeek.Wednesday, SelectablePeriodType = SelectablePeriodType.DayOfWeek });

            Days = new ObservableCollection<SelectablePeriod>();
            for (int i = 1; i <= 31; i++)
            {
                Days.Add(new SelectablePeriod() { Id = i, SelectablePeriodType = SelectablePeriodType.Day });
            }

            Months = new ObservableCollection<SelectablePeriod>();
            for (int i = 1; i <= 12; i++)
            {
                Months.Add(new SelectablePeriod() { Id = i, SelectablePeriodType = SelectablePeriodType.Month });
            }
        }

        private ScheduleType _ScheduleType;
        public ScheduleType ScheduleType
        {
            get { return _ScheduleType; }
            set { SetField(ref _ScheduleType, value, () => ScheduleType); }
        }

        private DateTimeOffset _Start;
        [XmlIgnore]
        public DateTimeOffset Start
        {
            get { return _Start; }
            set
            {
                if (SetField(ref _Start, value, () => Start))
                {
                    OnPropertyChanged("StartDate");
                    OnPropertyChanged("StartTime");
                }
            }
        }

        [XmlIgnore]
        public DateTime StartDate
        {
            get
            {
                return Start.Date;
            }
            set
            {
                Start = new DateTimeOffset(new DateTime(value.Year, value.Month, value.Day, Start.Hour, Start.Minute, Start.Second));
            }
        }

        [XmlIgnore]
        public DateTime StartTime
        {
            get
            {
                return Start.LocalDateTime;
            }
            set
            {
                Start = new DateTimeOffset(new DateTime(Start.Year, Start.Month, Start.Day, value.Hour, value.Minute, value.Second));
            }
        }

        public string StartString
        {
            get { return Start.ToString(CultureInfo.InvariantCulture); }
            set
            {
                if (!string.IsNullOrEmpty(value))
                    Start = DateTimeOffset.Parse(value, CultureInfo.InvariantCulture);
            }
        }

        private int _RecurEveryX;
        public int RecurEveryX
        {
            get { return _RecurEveryX; }
            set { SetField(ref _RecurEveryX, value, () => RecurEveryX); }
        }

        private DateTimeOffset? _LastExecution;
        [XmlIgnore]
        public DateTimeOffset? LastExecution
        {
            get { return _LastExecution; }
            set { SetField(ref _LastExecution, value, () => LastExecution); }
        }

        public string LastExecutionString
        {
            get { return string.Format(CultureInfo.InvariantCulture, "{0}", LastExecution); }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    LastExecution = DateTimeOffset.Parse(value, CultureInfo.InvariantCulture);
                }
                else
                {
                    LastExecution = null;
                }
            }
        }

        private ObservableCollection<SelectablePeriod> _DaysOfWeek;
        [XmlIgnore]
        public ObservableCollection<SelectablePeriod> DaysOfWeek
        {
            get { return _DaysOfWeek; }
            set { SetField(ref _DaysOfWeek, value, () => DaysOfWeek); }
        }

        private ObservableCollection<SelectablePeriod> _Days;
        [XmlIgnore]
        public ObservableCollection<SelectablePeriod> Days
        {
            get { return _Days; }
            set { SetField(ref _Days, value, () => Days); }
        }

        private ObservableCollection<SelectablePeriod> _Months;
        [XmlIgnore]
        public ObservableCollection<SelectablePeriod> Months
        {
            get { return _Months; }
            set { SetField(ref _Months, value, () => Months); }
        }

        public List<int> MonthsIds
        {
            get
            {
                return (from month in _Months
                        where month.Selected
                        select month.Id).ToList();
            }
            set
            {
                foreach (var month in _Months)
                {
                    month.Selected = value.Contains(month.Id);
                }
            }
        }

        public List<int> DaysOfWeekIds
        {
            get
            {
                return (from day in _DaysOfWeek
                        where day.Selected
                        select day.Id).ToList();
            }
            set
            {
                foreach (var day in _DaysOfWeek)
                {
                    day.Selected = value.Contains(day.Id);
                }
            }
        }

        public List<int> DaysIds
        {
            get
            {
                return (from day in _Days
                        where day.Selected
                        select day.Id).ToList();
            }
            set
            {
                foreach (var day in _Days)
                {
                    day.Selected = value.Contains(day.Id);
                }
            }
        }

        public override string ToString()
        {
            var sb = new StringBuilder();

            sb.Append(ScheduleType);
            sb.Append(" ");
            sb.Append("Start:");
            sb.Append(Start);
            sb.Append(" ");
            sb.Append("Last:");
            sb.Append(LastExecution);
            sb.Append(" ");
            switch (ScheduleType)
            {
                default:
                case ScheduleType.OneTime:
                    break;
                case ScheduleType.Daily:
                    sb.Append("Recur:");
                    sb.Append(RecurEveryX);
                    sb.Append(" ");
                    break;
                case ScheduleType.Weekly:
                    sb.Append("Recur:");
                    sb.Append(RecurEveryX);
                    sb.Append(" ");
                    sb.Append("DaysOfWeek:");
                    foreach (var item in DaysOfWeek.Where((d) => d.Selected))
                    {
                        sb.Append(item.Id);
                        sb.Append(",");
                    }
                    break;
                case ScheduleType.Monthly:
                    sb.Append("Days:");
                    foreach (var item in Days.Where((d) => d.Selected))
                    {
                        sb.Append(item.Id);
                        sb.Append(",");
                    }
                    sb.Append(" ");
                    sb.Append("Months:");
                    foreach (var item in Months.Where((d) => d.Selected))
                    {
                        sb.Append(item.Id);
                        sb.Append(",");
                    }
                    break;
            }

            return sb.ToString();
        }
    }

    public enum SelectablePeriodType
    {
        DayOfWeek,
        Day,
        Month,
    }

    public class SelectablePeriod : ModelBase
    {
        private static DateTimeFormatInfo DateTimeFormatInfo = new DateTimeFormatInfo();

        public string Name
        {
            get
            {
                switch (SelectablePeriodType)
                {
                    case SelectablePeriodType.DayOfWeek:
                        return ((DayOfWeek)Id).ToString();
                    case SelectablePeriodType.Day:
                    default:
                        return Id.ToString();
                    case SelectablePeriodType.Month:
                        return DateTimeFormatInfo.GetMonthName(Id);
                }
            }
        }

        private SelectablePeriodType _SelectablePeriodType;
        public SelectablePeriodType SelectablePeriodType
        {
            get { return _SelectablePeriodType; }
            set { SetField(ref _SelectablePeriodType, value, () => SelectablePeriodType); }
        }

        private bool _Selected;
        public bool Selected
        {
            get { return _Selected; }
            set { SetField(ref _Selected, value, () => Selected); }
        }

        private int _Id;
        public int Id
        {
            get { return _Id; }
            set { SetField(ref _Id, value, () => Id); }
        }
    }
}
